home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2007 December
/
PCWKCD1207B.iso
/
Blogowanie poza sfera
/
Flock 1.0 beta
/
flock-1.0RC3.en-US.win32.exe
/
flock
/
components
/
flockYoutubeService.js
< prev
next >
Wrap
Text File
|
2007-10-18
|
69KB
|
1,990 lines
// vim: ts=2 sw=2 expandtab cindent
//
// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2007
// http://flock.com
//
// This file may be used under the terms of of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// END FLOCK GPL
// Developer ID = 1aiV9CsTs3o
// Developer Secret = flock_is_open_source
const ENABLE_DEBUG = true; // switch to turn off slow debug code for production
function DEBUG(x) { if (ENABLE_DEBUG) debug("flockYouTubeService: "+x+"\n"); }
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
Components.utils.import("resource://gre/modules/JSON.jsm");
Components.utils.import("resource:///modules/FlockScheduler.jsm");
const YT_DEVID = "1aiV9CsTs3o";
const YT_DEVSECRET = "flock_is_open_source";
const YOUTUBE_CID = Components.ID('{DCB6A01E-7D4A-4C30-AB3D-9CC98C02F617}');
const YOUTUBE_CONTRACTID = '@flock.com/?photo-api-youtube;1';
const YOUTUBE_FAVICON = "http://www.youtube.com/favicon.ico";
const YOUTUBE_TITLE = "YouTube Web Service";
const SERVICE_ENABLED_PREF = "flock.service.youtube.enabled";
const CATEGORY_COMPONENT_NAME = "YouTube JS Component"
const CATEGORY_ENTRY_NAME = "youtube"
const FRIENDS_AVATAR_TIMEOUT = 5000; // in milliseconds
const FRIENDS_ACTIVITY_TIMEOUT = 500; // in milliseconds
const FLOCK_PHOTOPERSON_CONTRACTID = '@flock.com/photo-person;1';
const PROPERTY_BAG_CONTRACTID = "@mozilla.org/hash-property-bag;1";
const XHR_CONTRACTID = "@mozilla.org/xmlextras/xmlhttprequest;1";
const FLOCK_RDDS_CONTRACTID = "@flock.com/rich-dnd-service;1";
const OBS_TOPIC_XPCOMSHUTDOWN = "xpcom-shutdown";
const YOUTUBE_IDENTITY_URN_PREFIX = "urn:flock:identity:youtube:";
const PEOPLE_PROPERTIES = "chrome://flock/locale/people/people.properties";
const YOUTUBE_STRING_BUNDLE = "chrome://flock/locale/services/youtube.properties";
// From nsIXMLHttpRequest.idl
// 4: COMPLETED Finished with all operations.
const XMLHTTPREQUEST_READYSTATE_COMPLETED = 4;
const HTTP_CODE_OK = 200;
// The delay between two refreshes when the sidebar is closed (in seconds)
const YOUTUBE_REFRESH_INTERVAL = 3600; // 60 minutes
// The delay between two refreshes when the sidebar is open (in seconds)
const YOUTUBE_SHORT_INTERVAL = 3600; // 60 minutes
var gCompTK;
function getCompTK() {
if (!gCompTK) {
gCompTK = Cc["@flock.com/singleton;1"]
.getService(Ci.flockISingleton)
.getSingleton("chrome://browser/content/flock/services/common/load-compTK.js")
.wrappedJSObject;
}
return gCompTK;
}
function _getIdentityUrn(aAccountId, aUid) {
var result = YOUTUBE_IDENTITY_URN_PREFIX
+ aAccountId + ":"
+ aUid;
return result;
}
loadLibraryFromSpec("chrome://browser/content/flock/photo/photoAPI.js");
var gTimers = []; // For use with the scheduler
// String defaults... may be updated later through Web Detective
var gStrings = {
"domains": "youtube.com",
"userlogin": "http://www.youtube.com/login",
"userprofile": "http://www.youtube.com/profile?user=%accountid%",
"editprofile": "http://youtube.com/my_profile",
"inbox": "http://youtube.com/my_messages",
"noavatarimage": "no_videos_140.jpg"
};
function youtubeVideo() {
}
youtubeVideo.prototype= {
id: "",
thumbnail: "",
webPageUrl: "",
midSizePhoto: "",
largeSizePhoto: "",
title: "",
username: "",
userid: "",
is_public: "true",
is_video: "true",
has_miniView: "true",
svcShortName: 'youtube',
buildTooltip: function( ) {
// do we have to use document from the window to ceate elements? -- ja
var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
var win = wm.getMostRecentWindow('navigator:browser');
if (!win) return null;
var box = win.document.createElement('vbox');
box.setAttribute('style', 'max-width: 250px');
var title = win.document.createElement('label');
title.setAttribute('value', this.title );
title.setAttribute('crop', 'end');
box.appendChild(title);
if( this.length_seconds)
{
var lbl = win.document.createElement('label');
lbl.setAttribute('value', 'Length: ' + this.length_seconds + ' seconds');
box.appendChild(lbl);
}
if(this.rating_avg)
{
var lbl = win.document.createElement('label');
lbl.setAttribute('value', 'Rating: ' + this.rating_avg + ' (' + this.rating_count + ' times)');
box.appendChild(lbl);
}
if(this.view_count)
{
var lbl = win.document.createElement('label');
lbl.setAttribute('value', 'Views: ' + this.view_count );
box.appendChild(lbl);
}
if(!(this.length_seconds && this.rating_avg && this.view_count))
{
//if the tooltip does not these metadata -- show the author
var lbl = win.document.createElement('label');
lbl.setAttribute('value', this.username );
lbl.setAttribute('class', 'user');
box.appendChild(lbl);
}
var vbox = win.document.createElement('vbox');
var cbox = win.document.createElement('cbox');
var largeImg = win.document.createElement('image');
largeImg.setAttribute('src', this.midSizePhoto);
largeImg.setAttribute('style', 'margin-bottom: 2px;');
var spacer = win.document.createElement('spacer');
spacer.setAttribute('flex', '1');
cbox.appendChild(largeImg);
cbox.appendChild(spacer);
vbox.appendChild(cbox);
vbox.appendChild(box);
return vbox;
},
buildHTML: function ( ) {
var flashUrl = this.webPageUrl.replace(/\/\?v\=/,'/v/');
return '<object width="425" height="350">'
+ '<param name="movie" value="'+flashUrl+'"/>'
+ '<embed src="'+flashUrl+'" type="application/x-shockwave-flash" width="425" height="350"/>'
+ this.webPageUrl
+ '</object>';
},
buildBBCode: function ( ) {
var video = this.webPageUrl.replace(/\/\?v\=/,'/watch?v=');
return '[youtube]' + video + '[/youtube]'
},
buildMiniPage: function ( ) {
var theurl = this.webPageUrl.replace(/\/\?v\=/,'/v/');
return '<html><head><title>' + this.title + ' (' + this.username + ')</title></head>' +
'<body><object width="425" height="350">' +
'<param name="movie" value="'+theurl+'"/>' +
'<center><embed src="'+theurl+'&autoplay=1" type="application/x-shockwave-flash" width="425" height="350"/></object></center></body></html>';
},
QueryInterface: function(iid) {
if (!iid.equals(Ci.nsISupports) &&
!iid.equals(Ci.flockIPhoto)) {
throw Components.results.NS_ERROR_NO_INTERFACE;
}
return this;
}
};
youtubeVideo.prototype.__defineGetter__('metaData', function () {
var metaData = Cc["@mozilla.org/hash-property-bag;1"].createInstance(Ci.nsIWritablePropertyBag2);
metaData.setPropertyAsAString("title", this.title);
metaData.setPropertyAsAString("length", this.length_seconds);
metaData.setPropertyAsAString("views", this.view_count);
metaData.setPropertyAsAString("rating", this.rating_avg);
metaData.QueryInterface(Ci.nsIPropertyBag);
return metaData;
})
// ================================================
// ========== BEGIN youtubeService class ==========
// ================================================
function youtubeService()
{
this.obs = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
this.obs.addObserver(this, OBS_TOPIC_XPCOMSHUTDOWN, false);
this.acUtils = Components.classes["@flock.com/account-utils;1"]
.getService(Components.interfaces.flockIAccountUtils);
this.status = Components.interfaces.flockIWebService.STATUS_UNKNOWN;
this.url = "http://www.youtube.com";
this.mIsInitialized = false;
this._ctk = {
interfaces: [
"nsISupports",
"nsISupportsCString",
"nsIClassInfo",
"nsIObserver",
"flockIWebService",
"flockIMediaWebService",
"flockISocialWebService",
"flockIYoutubeService",
"flockIManageableWebService",
"flockIPollingService",
"flockIRichContentDropHandler"
],
shortName: "youtube",
fullName: "YouTube",
description: YOUTUBE_TITLE,
favicon: YOUTUBE_FAVICON,
CID: YOUTUBE_CID,
contractID: YOUTUBE_CONTRACTID,
accountClass: youtubeAccount,
needPassword: false
};
var sbs = Cc["@mozilla.org/intl/stringbundle;1"]
.getService(Ci.nsIStringBundleService);
var bundle = sbs.createBundle(YOUTUBE_STRING_BUNDLE);
this._channels = {
"special:added": {
title: bundle.GetStringFromName("flock.youtube.title.added"),
supportsSearch: false,
feed: "http://youtube.com/rss/global/recently_added.rss"
},
"special:featured": {
title: bundle.GetStringFromName("flock.youtube.title.featured"),
supportsSearch: false
},
"special:top_favorites": {
title: bundle.GetStringFromName("flock.youtube.title.topfav"),
supportsSearch: false,
feed: "http://youtube.com/rss/global/top_favorites.rss"
},
"special:rated": {
title: bundle.GetStringFromName("flock.youtube.title.rated"),
supportsSearch: false,
feed: "http://youtube.com/rss/global/top_rated.rss"
}
};
this._logger = Cc['@flock.com/logger;1'].createInstance(Ci.flockILogger);
this._logger.init('youtube');
this._profiler = Cc["@flock.com/profiler;1"].getService(Ci.flockIProfiler);
this.init();
}
// BEGIN nsIObserver interface
youtubeService.prototype.observe =
function youtubeService_observe(subject, topic, state)
{
switch (topic) {
case OBS_TOPIC_XPCOMSHUTDOWN:
{
this.obs.removeObserver(this, OBS_TOPIC_XPCOMSHUTDOWN);
}; break;
}
}
// END nsIObserver interface
youtubeService.prototype.init =
function youtubeService_init()
{
DEBUG(".init()");
// Prevent re-entry
if (this.mIsInitialized) return;
this.mIsInitialized = true;
var evtID = this._profiler.profileEventStart("youtube-init");
this.prefService = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
if ( this.prefService.getPrefType(SERVICE_ENABLED_PREF) &&
!this.prefService.getBoolPref(SERVICE_ENABLED_PREF) )
{
DEBUG("Pref "+SERVICE_ENABLED_PREF+" set to FALSE... not initializing.");
var catMgr = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
catMgr.deleteCategoryEntry("wsm-startup", CATEGORY_COMPONENT_NAME, true);
catMgr.deleteCategoryEntry("flockWebService", CATEGORY_ENTRY_NAME, true);
catMgr.deleteCategoryEntry("flockMediaProvider", CATEGORY_ENTRY_NAME, true);
return;
}
this.faves_coop = Components.classes['@flock.com/singleton;1']
.getService(Components.interfaces.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
this.account_root = this.faves_coop.accounts_root;
this.ytService = new this.faves_coop.Service(
"urn:youtube:service",
{
name: "youtube",
desc: "The YouTube Service",
loginURL: gStrings["userlogin"],
contactLabel: 'Contacts'
}
);
this.ytService.serviceId = YOUTUBE_CONTRACTID;
// Load Web Detective file
this.webDetective = this.acUtils.useWebDetective("youtube.xml");
for (var s in gStrings) {
gStrings[s] = this.webDetective.getString("youtube", s, gStrings[s]);
}
this.ytService.domains = gStrings["domains"];
this.urn = this.ytService.id();
this._updateFriendAvatarsComplete = false;
this._updateFriendActivityComplete = false;
this._friendActivityArray = [];
this._profiler.profileEventEnd(evtID, "");
}
youtubeService.prototype.getError =
function youtubeService_getError (aErrorType, aXML, aHTTPErrorCode) {
var error = Components.classes["@flock.com/error;1"].createInstance(Ci.flockIError);
if (aErrorType == "HTTP_ERROR") {
error.errorCode = aHTTPErrorCode;
} else if (aErrorType == "SERVICE_ERROR") {
var errorCode;
var errorMessage;
var serviceErrorMessage;
try {
errorCode = aXML.getElementsByTagName("error")[0].getAttribute('code');
serviceErrorMessage = aXML.getElementsByTagName("error")[0].getAttribute('description');
} catch (ex) {
errorCode = "999" // in case the error xml is invalid
}
switch (errorCode) { // http://www.youtube.com/dev_error_codes
case "1":
error.errorCode = error.HTTP_INTERNAL_SERVER_ERROR;
break;
case "2": // These errors are due to Flock sending a bad request
case "3":
case "4":
case "5":
case "6":
error.errorCode = error.PHOTOSERVICE_INVALID_QUERY;
break;
case "7":
case "8":
error.errorCode = error.PHOTOSERVICE_INVALID_API_KEY;
break;
case "999":
error.errorCode = error.PHOTOSERVICE_UNKNOWN_ERROR;
break;
default:
error.errorCode = error.PHOTOSERVICE_UNKNOWN_ERROR;
break;
}
}
error.serviceErrorCode = errorCode;
error.serviceErrorString = serviceErrorMessage;
this._logger.error(error.errorString);
return error;
};
youtubeService.prototype.supportsSearch =
function youtubeService_supportsSearch( aQueryString ) {
var aQuery = new queryHelper(aQueryString);
if (aQuery.special) {
var channel = this._channels["special:" + aQuery.special];
if (channel) {
return channel.supportsSearch;
}
}
// none of the other apis/feeds support search
return false;
}
youtubeService.prototype.call =
function youtubeService_call(aListener, aMethod, aParams)
{
var url = "http://www.youtube.com/api2_rest?method=" + aMethod + "&dev_id=" + YT_DEVID;
for (p in aParams) {
url += "&" + p + "=" + aParams[p];
}
var hr = Components.classes['@mozilla.org/xmlextras/xmlhttprequest;1']
.createInstance(Components.interfaces.nsIXMLHttpRequest)
.QueryInterface(Components.interfaces.nsIJSXMLHttpRequest);
var inst = this;
hr.onreadystatechange = function (aEvt) {
if (hr.readyState == 4) {
try {
if (hr.status/100 == 2) {
var rsp = hr.responseXML.getElementsByTagName("ut_response")[0];
var stat = rsp.getAttribute("status");
if (stat != "ok") {
var error = inst.getError('SERVICE_ERROR', hr.responseXML, null);
aListener.onError(error);
}
else {
aListener.onResult(hr.responseXML);
}
}
else {
// http errors
aListener.onError(inst.getError("HTTP_ERROR", null, hr.status));
}
} catch(e) {
// XMHTTPERROR (connection lost)
inst._logger.error(e);
aListener.onError(inst.getError("HTTP_ERROR", null, "9001"));
}
}
};
hr.backgroundRequest = true;
hr.open('GET', url,true);
hr.send(null);
}
youtubeService.prototype.getFeed =
function youtubeService_getFeed(aListener, aFeedURL)
{
ios = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var uri = ios.newURI(aFeedURL, null, null);
var ytServ = this;
var feedListener = {
onGetFeedComplete: function oncomplete (feed) {
ytServ.handleFeedResult(aListener, feed);
},
onError: aListener.onError
};
var fm = Components.classes["@flock.com/feed-manager;1"]
.getService(Components.interfaces.flockIFeedManager);
fm.getFeedBypassCache(uri, feedListener);
}
youtubeService.prototype.createAlbum =
function youtubeService_createAlbum(aListener, aAlbumName)
{
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
}
youtubeService.prototype.findByUsername =
function youtubeService_findByUsername(aListener, aUsername)
{
var inst = this;
var myListener = {
onResult: function (aXML) {
var newUserObj = Components.classes[FLOCK_PHOTOPERSON_CONTRACTID]
.createInstance(Components.interfaces.flockIPhotoPerson);
newUserObj.service = inst;
newUserObj.id = aUsername;
newUserObj.username = aUsername;
newUserObj.fullname = aUsername;
aListener.onFindByUsernameResult(newUserObj);
},
onError: function (aXML) {
aListener.onError(aXML);
}
}
var params = {};
params.user = aUsername;
this.call(myListener, "youtube.users.get_profile", params);
}
youtubeService.prototype.getAlbums = function(aListener, aUsername) { throw Components.results.NS_ERROR_NOT_IMPLEMENTED; }
youtubeService.prototype.getAuthPerson = function() {
if (!this.user) return null;
var newUserObj = Components.classes[FLOCK_PHOTOPERSON_CONTRACTID]
.createInstance(Components.interfaces.flockIPhotoPerson);
newUserObj.id = this.api.user.username
newUserObj.username = this.api.user.username;
newUserObj.fullname = this.api.user.username;
newUserObj.service = this;
return newUserObj;
}
youtubeService.prototype.getContacts = function(aListener) { throw Components.results.NS_ERROR_NOT_IMPLEMENTED; }
youtubeService.prototype.getMostRecentPhotoForList = function(aListener, aEnumerator) { throw Components.results.NS_ERROR_NOT_IMPLEMENTED; }
youtubeService.prototype.getPhoto = function(aListener, aPhotoID) { throw Components.results.NS_ERROR_NOT_IMPLEMENTED; }
youtubeService.prototype.login = function(aAccountURN, aListener) { throw Components.results.NS_ERROR_NOT_IMPLEMENTED; }
youtubeService.prototype.queryChannel =
function youtubeService_queryChannel(aListener, aQueryString, aCount, aPage)
{
var aQuery = new queryHelper(aQueryString);
// return; // XXX TODO FIXME: This is killing perf
var inst = this;
var myListener = {
onResult: function (aXML) {
var rval = inst.handlePhotosResult(aXML);
var enum_ = {
hasMoreElements: function() {
return (rval.length > 0);
},
getNext: function() {
return rval.shift();
}
}
aListener.onSearchResult(enum_);
},
onError: function (aError) {
aListener.onError(aError);
}
}
var params = {}
if (aQuery.search) {
params.tag = aQuery.search;
params.page = aPage;
params.per_page = aCount;
this.call(myListener, 'youtube.videos.list_by_tag', params);
} else {
// this API call doesn't support pagination and only shows most recent 25 items
if (aPage > 1) return;
var channel = this._channels[aQuery.stringVal];
if (!channel) return;
if (channel.feed)
this.getFeed(aListener, channel.feed);
else
this.call(myListener, "youtube.videos.list_featured", params);
}
}
youtubeService.prototype.search =
function youtubeService_search( aListener, aQueryString, aCount, aPage )
{
var aQuery = new queryHelper(aQueryString);
if (aPage > 1) return; // youtube doesn't support pagination
if(aQuery.favorites && !aQuery.user)
{
aQuery.user = aQuery.favorites;
}
if (!aQuery.user && aQuery.special != "favorites") {
this.queryChannel( aListener, aQueryString, aCount, aPage );
return;
}
var aUserid = aQuery.user;
var params = {
user: aUserid
};
var inst = this;
var myListener = {
onResult: function (aXML) {
var rval = inst.handlePhotosResult(aXML, aUserid);
var enum_ = {
hasMoreElements: function() {
return (rval.length > 0);
},
getNext: function() {
return rval.shift();
}
}
aListener.onSearchResult(enum_);
},
onError: function (aError) {
aListener.onError(aError);
}
}
if (aQuery.favorites) {
this.call(myListener, "youtube.users.list_favorite_videos", params);
} else {
this.call(myListener, "youtube.videos.list_by_user", params);
}
}
youtubeService.prototype.getPhotoFromRDFNode =
function (aRDFId)
{
var newPhoto = new youtubeVideo();
var coopPhoto = this.faves_coop.get(aRDFId);
newPhoto.webPageUrl = coopPhoto.URL;
newPhoto.thumbnail = coopPhoto.thumbnail;
newPhoto.midSizePhoto = coopPhoto.midSizePhoto;
newPhoto.largeSizePhoto = coopPhoto.largeSizePhoto;
newPhoto.username = coopPhoto.username;
newPhoto.userid = coopPhoto.userid;
newPhoto.title = coopPhoto.name;
newPhoto.id = coopPhoto.photoid;
newPhoto.icon = coopPhoto.favicon;
newPhoto.uploadDate = coopPhoto.datevalue;
newPhoto.is_public = coopPhoto.is_public;
newPhoto.is_video = "true";
return newPhoto;
// JMC XXX TODO: Gotta add the video-specific fields into the RDF, or somewhere
// eg content length, rating, etc.
}
youtubeService.prototype.handlePhotosResult =
function youtubeService_handlePhotoResult(aXML, aUserid)
{
var rval = [];
var photoList = aXML.getElementsByTagName("video");
for (var i = 0; i < photoList.length; i++) {
var photo = photoList[i];
var newPhoto = new youtubeVideo();
for (var j = 0; j < photo.childNodes.length; j++)
{
var child = photo.childNodes[j];
var contentNode = child.childNodes[0];
var childContent = "";
if (contentNode) childContent = contentNode.nodeValue;
switch (child.tagName)
{
case "author":
newPhoto.username = childContent;
newPhoto.userid = childContent;
break;
// case "id": newPhoto.id = childContent; break;
case "title": newPhoto.title = childContent; break;
case "upload_time":
newPhoto.uploadDate = childContent * 1000;
newPhoto.id = parseInt(childContent);
break;
case "length_seconds":
newPhoto.length_seconds = childContent;
break
case "rating_avg":
newPhoto.rating_avg = childContent;
break
case "description":
newPhoto.description = childContent;
break
case "comment_count":
newPhoto.comment_count = childContent;
break
case "view_count":
newPhoto.view_count = childContent;
break
case "rating_count":
newPhoto.rating_count = childContent;
break
case "url":
newPhoto.webPageUrl = childContent;
break;
case "thumbnail_url":
newPhoto.thumbnail = childContent;
newPhoto.midSizePhoto = childContent;
newPhoto.largeSizePhoto = childContent;
break;
// case "id": newPhoto.id = childContent;
// break;
}
}
newPhoto.is_public = "true";
newPhoto.is_video = true;
rval.push(newPhoto);
}
return rval;
}
youtubeService.prototype.handleFeedResult =
function youtubeService_handleFeedResult(aListener, aFeed)
{
var photos = [];
var items = aFeed.getItems();
while (items && items.hasMoreElements()) {
var item = items.getNext();
var newPhoto = new youtubeVideo();
newPhoto.title = item.getTitle();
newPhoto.webPageUrl = item.getLink().spec;
newPhoto.uploadDate = item.getPubDate();
newPhoto.id = newPhoto.uploadDate / 1000;
var author = item.getAuthor();
newPhoto.username = author;
newPhoto.userid = author;
var desc = item.getContent();
var re = /<img [^>]*src="([^"]*)"/i;
var thumbnail = desc.match(re)[1];
newPhoto.thumbnail = thumbnail;
newPhoto.midSizePhoto = thumbnail;
newPhoto.largeSizePhoto = thumbnail;
newPhoto.is_public = "true";
newPhoto.is_video = true;
photos.push(newPhoto);
}
var enum_ = {
hasMoreElements: function() {
return (photos.length > 0);
},
getNext: function() {
return photos.shift();
}
}
aListener.onSearchResult(enum_);
}
youtubeService.prototype.supportsFeature = function(aFeature) {
var supports = {};
supports.tags = true;
supports.title = true;
supports.fileName = false;
supports.contacts = true;
supports.privacy = false;
supports.albumCreation = false;
return (supports[aFeature] == true);
}
youtubeService.prototype.upload = function(aListener, aFile, aParams, aUpload) { throw Components.results.NS_ERROR_NOT_IMPLEMENTED; }
youtubeService.prototype.refresh =
function youtubeService_refresh(aURN, aListener)
{
DEBUG("refresh with aURN of " + aURN);
var refreshItem = this.faves_coop.get(aURN);
if (refreshItem.isInstanceOf(this.faves_coop.Account)) {
this._logger.debug("refreshing an Account");
if (refreshItem.isAuthenticated) {
this.refreshAccount(aURN, aListener);
} else {
// If the user is not logged in, return a success without
// refreshing anything
aListener.onResult();
}
} else {
throw Components.results.NS_ERROR_ABORT;
}
}
youtubeService.prototype.refreshAccount =
function youtubeService_refreshAccount(aURN, aListener)
{
if (!aURN) return;
var inst = this;
var coopAcct = this.faves_coop.get(aURN);
var individualSuccess = {};
individualSuccess.numberOfAnswers = 0;
individualSuccess.listener = aListener;
individualSuccess.coopAcct = coopAcct;
individualSuccess.refreshNumber = 3;
// get friends
var getFriendsListener = {
onResult: function getFriendsListener_onResult(aXML) {
inst._handleFriendsResult(aXML, coopAcct, individualSuccess);
},
onError: function getFriendsListener_onError(aXML) {
inst._logger.error("Error on getFriendsListener");
}
}
// get new message count
var hr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
hr.onreadystatechange = function updateUserAccount_onreadystatechange(aEvent) {
if (hr.readyState == 4) {
var results = Cc["@mozilla.org/hash-property-bag;1"]
.createInstance(Ci.nsIWritablePropertyBag2);
if (inst.webDetective.detectNoDOM("youtube", "accountinfo", "",
hr.responseText, results))
{
// Set the message count
var messages = 0;
var msgCount = results.getPropertyAsAString("messages");
if (msgCount && msgCount.length) {
messages = msgCount;
}
inst._logger.debug("coopAcct.accountMessages " + messages);
if (coopAcct.accountMessages < messages) {
inst._lightPeopleIcon();
}
coopAcct.accountMessages = messages;
// Set the avatar for the mecard.
// If avatar returned as YT no avatar, then set coop avatar to
// null and let people sidebar code set the Flock no avatar img.
if (results.getPropertyAsAString("avatar")
.match(gStrings["noavatarimage"])) {
coopAcct.avatar = null;
inst._logger.debug("no avatar for account, setting to null\n");
} else {
var avatar = results.getPropertyAsAString("avatar");
coopAcct.avatar = inst._fixRelativeAvatarUrl(avatar);
inst._logger.debug("coopAcct.accountAvatar " + coopAcct.avatar);
}
} else {
coopAcct.accountMessages = 0;
}
inst._onIndividualSuccess(individualSuccess);
}
}
hr.open("GET", gStrings["userprofile"].replace("%accountid%", coopAcct.id()));
hr.send(null);
var params = {};
params.user = coopAcct.accountId;
this.call(getFriendsListener, "youtube.users.list_friends", params);
}
youtubeService.prototype._onIndividualSuccess =
function youtubeService__onIndividualSuccess(aObj) {
aObj.numberOfAnswers++;
if (aObj.numberOfAnswers >= aObj.refreshNumber) {
if (this.acUtils.isPeopleSidebarOpen()) {
aObj.coopAcct.nextRefresh = new Date(Date.now()
+ YOUTUBE_SHORT_INTERVAL * 1000);
}
if (aObj.listener) {
aObj.listener.onResult();
}
}
}
youtubeService.prototype.markAllMediaSeen =
function youtubeService_markAllMediaSeen(aIdentityUrn) {
var identity = this.faves_coop.get(aIdentityUrn);
identity.unseenMedia = 0;
}
youtubeService.prototype._lightPeopleIcon =
function youtubeService__lightPeopleIcon() {
this._logger.debug("._lightPeopleIcon()");
this.obs.notifyObservers(null, "new-people-notification", null);
}
youtubeService.prototype._updateFriendAvatars =
function youtubeService__updateFriendAvatars(aURN, aInvidualSuccessObj) {
this._logger.info("._updateFriendAvatars");
if (this._updateFriendAvatarsComplete || !aURN) {
return;
}
// Array of friends accounts (coop objects, not URNs) used to get avatars
var friendsList = [];
// Retrieve the account's friends list and add friends currently without an
// avatar to a list to be updated at a later time
var friendsEnum = this.faves_coop.get(aURN).friendsList.children.enumerate();
while (friendsEnum.hasMoreElements()) {
var friend = friendsEnum.getNext();
if (friend.avatar == "") {
this._logger.debug("adding friend with missing avatar for updating: "
+ friend.accountId + "\n");
friendsList.push(friend);
// Increment number count that onIndividualSucess needs to count to
aInvidualSuccessObj.refreshNumber++;
}
}
var inst = this;
var friendsTimerCallback = {
notify: function friendNotify(aTimer) {
// Scrape the friend page for their avatar
if (friendsList.length > 0) {
var friend = friendsList.shift();
var page = gStrings["userprofile"]
.replace("%accountid%", friend.accountId);
var xhr = Cc[XHR_CONTRACTID].createInstance(Ci.nsIXMLHttpRequest);
xhr.open("GET", page, true);
xhr.onreadystatechange = function friend_OnReadyStateChange(aEvent) {
if (xhr.readyState == XMLHTTPREQUEST_READYSTATE_COMPLETED) {
if (xhr.status == HTTP_CODE_OK) {
var results = Cc[PROPERTY_BAG_CONTRACTID]
.createInstance(Ci.nsIWritablePropertyBag2);
if (inst.webDetective.detectNoDOM("youtube", "page", "",
xhr.responseText, results))
{
// If avatar returned as YT no avatar, then set coop avatar to
// null and let people sidebar code set the Flock no avatar img.
if (results.getPropertyAsAString("avatar")
.match(gStrings["noavatarimage"])) {
friend.avatar = null;
inst._logger.debug("no avatar for friend: " + friend.accountId + "\n");
} else {
friend.avatar = results.getPropertyAsAString("avatar");
friend.avatar = inst._fixRelativeAvatarUrl(friend.avatar);
inst._logger.debug("found friend's avatar: " + friend.accountId
+ ", " + friend.avatar + "\n");
}
}
inst._onIndividualSuccess(aInvidualSuccessObj);
}
}
}
inst._logger.debug("requesting avatar for: " + page + "\n");
xhr.send(null);
}
// Kill the timer if there's nothing left to update in the array
if (friendsList.length < 1) {
inst._logger.debug("no friends without avatars left to update, "
+ "kill the timer");
inst._friendsTimer.cancel();
inst._friendsTimer = null;
}
}
};
// Start the timer to update the account's friends avatars
if (!this._friendsTimer && friendsList.length > 0) {
this._logger.debug("found friends without avatars to update, "
+ "start the timer");
this._friendsTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._friendsTimer.initWithCallback(friendsTimerCallback,
FRIENDS_AVATAR_TIMEOUT,
Ci.nsITimer.TYPE_REPEATING_SLACK);
// Once we've started updating friends without avatars, we only want to
// check once per session so as not to incur a performance hit
this._updateFriendAvatarsComplete = true;
}
}
youtubeService.prototype._updateFriendAvatar =
function youtubeService__updateFriendAvatar(aDocument, aAccountID) {
if (aDocument && aAccountID) {
var results = Cc[PROPERTY_BAG_CONTRACTID]
.createInstance(Ci.nsIWritablePropertyBag2);
if (this.webDetective.detect("youtube", "page", aDocument, results)) {
var friendID = results.getPropertyAsAString("friend");
// Only need to update the friend avatar if we're visiting the friend's page
if (aAccountID != friendID) {
var friendURN = _getIdentityUrn(aAccountID, friendID);
if (friendURN) {
var friend = this.faves_coop.get(friendURN);
var avatar = results.getPropertyAsAString("avatar");
avatar = this._fixRelativeAvatarUrl(avatar);
// Only need to update the friend avatar if it's changed
if (friend && friend.avatar != avatar) {
friend.avatar = avatar;
}
}
}
}
}
}
/**
* The avatar URL we scraped may be a relative URL. If so, prepend
* "http://www.youtube.com/" to it.
*/
youtubeService.prototype._fixRelativeAvatarUrl =
function youtubeService__fixRelativeAvatarUrl(aUrl) {
var url = aUrl;
if (url.indexOf("http") != 0) {
url = "http://www.youtube.com";
// Do we need to add a leading slash?
if (aUrl.indexOf("/") != 0) {
url += "/";
}
url += aUrl;
}
return url;
}
youtubeService.prototype._personUpdateRequired =
function youtubeService__personUpdateRequired(aCoopPerson, aPerson) {
return (aCoopPerson.name != aPerson.accountId);
}
youtubeService.prototype.addCoopPerson =
function youtubeService_addCoopPerson(aPhotoPerson, aCoopAccount)
{
var person = aPhotoPerson;
var identityUrn = _getIdentityUrn(aCoopAccount.accountId,
person.accountId);
var updating = this.faves_coop.Identity.exists(identityUrn);
var identity;
if (updating) {
identity = this.faves_coop.get(identityUrn);
if (this._personUpdateRequired(aCoopAccount,person)) {
// Update data of the identity coop obj here
identity.name = person.accountId;
this._incrementMedia(identity, person);
}
} else {
identity = new this.faves_coop.Identity(
identityUrn,
{
name: person.accountId,
serviceId: YOUTUBE_CONTRACTID,
accountId: person.accountId,
avatar: "",
statusMessage: "",
lastUpdateType: "media",
lastUploadedMedia: person.videoCount
}
);
aCoopAccount.friendsList.children.add(identity);
this._addIdentityToActivityArray(identity);
}
}
youtubeService.prototype._addIdentityToActivityArray =
function youtubeService__addIdentityToActivityArray(aIdentity) {
this._logger.info("._addIdentityToActivityArray('"+ aIdentity.name + "')");
//only want to add to array when friendsActivity timer is ready
if (!this._updateFriendActivityComplete) {
this._friendActivityArray.push(aIdentity);
}
}
youtubeService.prototype._incrementMedia =
function youtubeService__incrementMedia(identity, person) {
this._logger.info("._incrementMedia('"+identity.id() + "," + person.accountId +"')");
if (identity.lastUploadedMedia != person.videoCount) {
identity.lastUploadedMedia = person.videoCount;
identity.unseenMedia = 1;
this._addIdentityToActivityArray(identity);
}
}
youtubeService.prototype._updateFriendRecentActivity =
function youtubeService__updateFriendRecentActivity(aIndividualSuccess) {
this._logger.info("._updateFriendRecentActivity");
var success = aIndividualSuccess;
if (this._updateFriendActivityComplete ||
this._friendActivityArray.length == 0)
{
this._onIndividualSuccess(success);
return;
}
// We are successful for refresh after each friend in _friendActivityArray
// list is updated
success.refreshNumber += (this._friendActivityArray.length -1);
var inst = this;
var friendsTimerCallback = {
notify: function friendNotify(aTimer) {
inst._updateFriendActivityComplete = true;
while(inst._friendActivityArray.length != 0)
{
var identity = inst._friendActivityArray.pop();
inst._updateLastUpdateDate(identity, success);
inst._logger.info("updating recent activity for " + identity.name);
}
inst._logger.debug("no friends without avatars left to update, "
+ "kill the timer");
inst._friendsActivityTimer.cancel();
inst._friendsActivityTimer = null;
inst._updateFriendActivityComplete = false;
inst._friendActivityArray = null;
inst._friendActivityArray = [];
inst._logger.info("done updating recent activity");
}
};
// Start the timer to update the account's friends avatars
if (!this._friendsActivityTimer) {
this._logger.debug("found friends without avatars to update, "
+ "start the timer");
this._friendsActivityTimer = Cc["@mozilla.org/timer;1"]
.createInstance(Ci.nsITimer);
this._friendsActivityTimer.initWithCallback(friendsTimerCallback,
FRIENDS_ACTIVITY_TIMEOUT,
Ci.nsITimer.TYPE_REPEATING_SLACK);
this._updateFriendActivityComplete = false;
}
}
youtubeService.prototype._updateLastUpdateDate =
function youtubeService__updateLastUpdateDate(aIdentity, aInvidualSuccessObj)
{
this._logger.info("._updateLastUpdateDate('"+ aIdentity.name + "')");
var identity = aIdentity;
var params = {
user: identity.name,
page: 1,
per_page: 1,
};
var inst = this;
var myListener = {
onResult: function (aXML) {
inst._logger.info("onResult");
var video = inst.handlePhotosResult(aXML);
if (video.length == 1) {
video = video[0];
//Youtube gives us UNIX time in seconds, change to miliseconds
var time = video.uploadDate / 1000;
identity.lastUpdate = time;
}
inst._onIndividualSuccess(aInvidualSuccessObj);
},
onError: function (aError) {
if (!identity.lastUpdate) {
identity.lastUpdate = inst._numberFromString(identity.name);
}
}
};
this.call(myListener, "youtube.videos.list_by_user", params);
}
youtubeService.prototype._handleFriendsResult =
function youtubeService__handleFriendsResult(aXML, aAccount,
aInvidualSuccessObj)
{
DEBUG("._handleFriendsResult(aXML, aAccount)");
var friendList = aXML.getElementsByTagName("friend");
var inst = this;
var peopleHash = [];
DEBUG(" - found "+friendList.length+" friends");
for (var i = 0; i < friendList.length; i++) {
var friend = friendList[i];
var friendObj = {};
for (var j = 0; j < friend.childNodes.length; j++)
{
var child = friend.childNodes[j];
var contentNode = child.childNodes[0];
var childContent = "";
if (contentNode) childContent = contentNode.nodeValue;
switch (child.tagName)
{
case "user":
friendObj.accountId = childContent;
friendObj.name = childContent;
break;
case "video_upload_count":
friendObj.videoCount = childContent;
break;
}
}
peopleHash[friendObj.accountId] = friendObj;
peopleHash[friendObj.accountId].media = {
count: 1,
latest: friendObj.videoCount
};
}
function myWorker(aShouldYield) {
// ADD or update existing people
for (var uid in peopleHash) {
inst.addCoopPerson(peopleHash[uid], aAccount);
if (aShouldYield()) {
yield;
}
}
// REMOVE locally people removed on the server
var localEnum = aAccount.friendsList.children.enumerate();
while (localEnum.hasMoreElements()) {
var identity = localEnum.getNext();
if (!peopleHash[identity.accountId]) {
inst._logger.info("Friend " + identity.accountId
+ " has been deleted on the server");
aAccount.friendsList.children.remove(identity);
identity.destroy();
}
}
inst._onIndividualSuccess(aInvidualSuccessObj);
inst._updateFriendRecentActivity(aInvidualSuccessObj);
inst._updateFriendAvatars(aAccount.id(), aInvidualSuccessObj);
} // end myWorker()
FlockScheduler.schedule(null, 0.05, 10, myWorker);
}
var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript("chrome://browser/content/utilityOverlay.js");
// BEGIN flockIWebService interface
youtubeService.prototype.addAccountById =
function youtubeService_addAccountById(aAccountID, aIsTransient, aListener)
{
DEBUG("{flockIWebService}.addAccountById('"+aAccountID+"', "+aIsTransient+", aListener)");
var accountURN = "urn:flock:youtube:"+aAccountID;
var account = this.faves_coop.get(accountURN);
if (!account) {
account = new this.faves_coop.Account(
accountURN,
{
name: aAccountID,
serviceId: YOUTUBE_CONTRACTID,
service: this.ytService,
accountId: aAccountID,
URL: gStrings["userprofile"].replace("%accountid%", aAccountID),
isTransient: aIsTransient,
refreshInterval: YOUTUBE_REFRESH_INTERVAL,
favicon: YOUTUBE_FAVICON
}
);
this.account_root.children.add(account);
}
if (!account.friendsList) {
var friendsListUrn = accountURN + ":friends";
var friendsList = new this.faves_coop.FriendsList(
friendsListUrn,
{
account: account
}
);
account.friendsList = friendsList;
}
this.USER = account.id();
// Instanciate account component
var acct = this.getAccount(account.id());
if (aListener) aListener.onSuccess(acct, "addAccount");
return acct;
}
// END flockIWebService interface
// BEGIN flockIManageableWebService interface
youtubeService.prototype.updateAccountStatusFromDocument =
function youtubeService_updateAccountStatusFromDocument(aDocument)
{
this._logger.info("{flockIManageableWebService}.updateAccountStatusFromDocument()");
if (this.webDetective.detect("youtube", "loggedout", aDocument, null))
{
this.acUtils.markAllAccountsAsLoggedOut(YOUTUBE_CONTRACTID);
} else if (this.webDetective.detect("youtube", "loggedin", aDocument, null)) {
var results = Components.classes["@mozilla.org/hash-property-bag;1"]
.createInstance(Components.interfaces.nsIWritablePropertyBag2);
if (this.webDetective.detect("youtube", "accountinfo", aDocument, results)) {
var accountID = results.getPropertyAsAString("accountid");
if (accountID && accountID.length) {
var accountURN = this.acUtils.getAccountURNById(this.urn, accountID);
var acct = this.faves_coop.get(accountURN);
if (!acct.isAuthenticated) {
var inst = this;
var loginListener = {
onSuccess: function loginListener_onSuccess() {
inst._logger.debug(".updateAccountStatusFromDocument(): "
+ "loginListener: onSuccess()");
acct.isAuthenticated = true;
inst._updateFriendAvatarsComplete = false;
},
onError: function loginListener_onError(aError) {
inst._logger.debug(".updateAccountStatusFromDocument(): "
+ "loginListener: onError()");
inst._logger.debug(aError ? (aError.errorString) : "No details");
}
};
this.getAccount(accountURN).login(loginListener);
}
}
}
}
}
// END flockIManageableWebService interface
// BEGIN flockISocialWebService interface
// END flockISocialWebService interface
// BEGIN flockIMediaWebService interface
youtubeService.prototype.migrateAccount =
function youtubeService_migrateAccount(aId, aUsername) {
this.init();
this.addAccountById(aId, false, null);
}
youtubeService.prototype.decorateForMedia =
function youtubeService_decorateForMedia(aDocument)
{
DEBUG("{flockIMediaWebService}.decorateForMedia(aDocument)");
aDocument.QueryInterface(Components.interfaces.nsIDOMHTMLDocument);
var results = Components.classes["@mozilla.org/hash-property-bag;1"]
.createInstance(Components.interfaces.nsIWritablePropertyBag2);
if (this.webDetective.detect("youtube", "media", aDocument, results)) {
var mediaArr = [];
// media item for user videos
var userid = results.getPropertyAsAString("userid");
var media = {
name: userid,
query: 'user:' + userid + "|username:" + userid,
label: userid + "'s Videos", // FIXME: breaks internationalization
favicon: this.icon,
service: this.shortName
}
mediaArr.push(media);
// media item for user favorites
var media = {
name: userid,
query: 'favorites:' + userid,
label: userid + "'s Favorites", // FIXME: breaks internationalization
favicon: this.icon,
service: this.shortName
}
mediaArr.push(media);
if (!aDocument._flock_decorations) {
aDocument._flock_decorations = {};
}
aDocument._flock_decorations.mediaArr = mediaArr;
this.obs.notifyObservers(aDocument, 'media', 'media:update');
}
}
youtubeService.prototype.handlesMediaStream =
function youtubeService_handlesMediaStream()
{
return true;
}
youtubeService.prototype.checkIsStreamUrl =
function youtubeService_checkIsStreamUrl(aUrl)
{
if (this.webDetective.detectNoDOM("youtube", "isStreamUrl", "", aUrl, null)) {
this._logger.debug("Checking if url is youtube stream: YES: " + aUrl);
return true;
}
this._logger.debug("Checking if url is youtube stream: NO: " + aUrl);
return false;
}
youtubeService.prototype.getVideoIDFromUrl =
function youTubeService_getVideoIDFromUrl(aUrl)
{
var videoId = null;
//http://www.youtube.com/v/lp_daXRkOH0
//http://www.youtube.com/watch/v/YP2rgi978tw
//http://www.youtube.com/watch?v=BjfbS_Kj-J0
// /player2.swf?video_id=xPxDw7ajfGE&....
var detectResults = Cc["@mozilla.org/hash-property-bag;1"]
.createInstance(Ci.nsIWritablePropertyBag2);
if (this.webDetective.detectNoDOM("youtube", "videoId", "", aUrl, detectResults)) {
videoId = detectResults.getPropertyAsAString("videoId");
}
return videoId;
}
youtubeService.prototype.getMediaQueryFromURL =
function youTubeService_getMediaQueryFromURL(aUrl, aListener)
{
var videoId = this.getVideoIDFromUrl(aUrl);
if (videoId) {
var myListener = {
onResult: function (aXML) {
var userID = aXML.getElementsByTagName('author')[0].firstChild.nodeValue;
var results = Components.classes["@mozilla.org/hash-property-bag;1"]
.createInstance(Components.interfaces.nsIWritablePropertyBag2);
results.setPropertyAsAString("query", "user:" + userID + "|username:" + userID);
// Note: The "title" property is currently not used by the media bar.
results.setPropertyAsAString("title", userID);
aListener.onSuccess(results, "query");
},
onError: function (aError) {
aListener.onError(null, aError, null);
}
}
var params = {};
params.video_id = videoId;
this.call(myListener, "youtube.videos.get_details", params);
} else {
aListener.onError(null, "Unable to get user.", null);
}
}
// END flockIMediaWebService interface
// Checks if the TEXTAREA is drag and droppable
youtubeService.prototype._isDnDableTextarea =
function youtubeService__isDnDableTextarea(aDocument, aXPath, aTextarea)
{
if (aDocument && aXPath && aTextarea) {
var xpath = this.webDetective.getString("youtube", aXPath, "");
var results = aDocument.evaluate(xpath, aDocument, null,
Ci.nsIDOMXPathResult.ANY_TYPE, null);
if (results && results.iterateNext() == aTextarea) {
return true;
}
}
return false;
}
// BEGIN flockIRichContentDropHandler
youtubeService.prototype.handleDrop =
function youtubeService_handleDrop(aFlavours, aTextarea)
{
this._logger.info(".handleDrop()");
var dropCallback = function youtube_dropCallback(aFlav) {
var data = {}, len = {};
aFlavours.getTransferData(aFlav, data, len);
var caretPos = aTextarea.selectionEnd;
var currentValue = aTextarea.value;
// Add a trailing space so that we don't mangle the url
var nextChar = currentValue.charAt(caretPos);
var trailingSpace = ((nextChar == "") ||
(nextChar == " ") ||
(nextChar == "\n"))
? ""
: " ";
// Only add a breadcrumb if the insertion point is at the end of
// the text so that we don't duplicate breadcrumbs
var breadcrumb = (aTextarea.value.length == aTextarea.selectionEnd)
? Cc[FLOCK_RDDS_CONTRACTID]
.getService(Ci.flockIRichDNDService)
.getBreadcrumb("plain")
: "";
aTextarea.value = currentValue.substring(0, caretPos)
+ data.value.QueryInterface(Ci.nsISupportsString)
.data.replace(/: /, ":\n")
+ trailingSpace
+ currentValue.substring(caretPos)
+ breadcrumb;
};
return this._handleTextareaDrop(CATEGORY_ENTRY_NAME, this.ytService.domains,
aTextarea, dropCallback);
}
// END flockIRichContentDropHandler
youtubeService.prototype.maxStatusLength = 0;
// ========== END youtubeService class ==========
// ================================================
// ========== BEGIN youtubeAccount class ==========
// ================================================
function youtubeAccount()
{
this.acUtils = Components.classes["@flock.com/account-utils;1"]
.getService(Components.interfaces.flockIAccountUtils);
this.service = Components.classes[YOUTUBE_CONTRACTID]
.getService(Components.interfaces.flockIWebService)
.QueryInterface(Components.interfaces.flockISocialWebService);
this._coop = Components.classes["@flock.com/singleton;1"]
.getService(Components.interfaces.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
this.webDetective = Cc["@flock.com/web-detective;1"]
.getService(Ci.flockIWebDetective);
this._ctk = {
interfaces: [
"nsISupports",
"flockIWebServiceAccount",
"flockIMediaWebServiceAccount",
"flockISocialWebServiceAccount",
"flockIYoutubeAccount"
]
};
getCompTK().addAllInterfaces(this);
this._logger = Cc["@flock.com/logger;1"].createInstance(Ci.flockILogger);
this._logger.init("youtubeAccount");
}
// BEGIN flockIWebServiceAccount interface
youtubeAccount.prototype.urn = "";
youtubeAccount.prototype.username = "";
youtubeAccount.prototype.status = "";
youtubeAccount.prototype.activate =
function youtubeAccount_activate(aListener)
{
DEBUG("{flockIWebServiceAccount}.activate()");
var acctCoopObj = this._coop.get(this.urn);
acctCoopObj.isPollable = true;
if (aListener) {
aListener.onSuccess(this, "accountAuthorized");
}
}
youtubeAccount.prototype.login =
function youtubeAccount_login(aListener)
{
DEBUG("{flockIWebServiceAccount}.login()");
this.acUtils.ensureOnlyAuthenticatedAccount(this.urn);
// force refresh on login
var pollerSvc = Cc["@flock.com/poller-service;1"]
.getService(Ci.flockIPollerService);
pollerSvc.forceRefresh(this.urn);
aListener.onSuccess();
}
// END flockIWebServiceAccount interface
// BEGIN flockISocialWebServiceAccount interface
youtubeAccount.prototype.hasFriendActions = true;
youtubeAccount.prototype.isStatusSupported = false;
youtubeAccount.prototype.isStatusEditable = false;
youtubeAccount.prototype.isPostLinkSupported = false;
youtubeAccount.prototype.isMyMediaFavoritesSupported = true;
youtubeAccount.prototype.setStatus =
function youtubeAccount_setStatus(aStatusMessage, aListener)
{
this._logger.info("{flockISocialWebServiceAccount}.setStatus('"+aStatusMessage+"',"+
"'"+aListener+"')");
}
youtubeAccount.prototype.getEditableStatus =
function youtubeAccount_getEditableStatus()
{
this._logger.info("{flockISocialWebServiceAccount}.getEditableStatus()");
return "";
}
youtubeAccount.prototype.formatStatusForDisplay =
function youtubeAccount_formatStatusForDisplay(aStatusMessage)
{
return "";
}
youtubeAccount.prototype.getMeNotifications =
function youtubeAccount_getMeNotifications()
{
this._logger.info(".getMeNotifications()");
var sbs = Cc["@mozilla.org/intl/stringbundle;1"]
.getService(Ci.nsIStringBundleService);
var bundle = sbs.createBundle(YOUTUBE_STRING_BUNDLE);
var noties = [];
var inst = this;
function _addNotie(aType, aCount) {
var stringName = "flock.youtube.noties."
+ aType + "."
+ ((parseInt(aCount) <= 0) ? "none" : "some");
inst._logger.info("aType " + aType + ' aCount ' + aCount + ' name ' + stringName);
noties.push({
class: aType,
tooltip: bundle.GetStringFromName(stringName),
metricsName: aType,
count: aCount,
URL: inst.webDetective.getString("youtube", aType + "_URL", "")
});
}
var c_acct = this._coop.get(this.urn);
_addNotie("meMessages", c_acct.accountMessages);
return JSON.toString(noties);
}
youtubeAccount.prototype.markAllMeNotificationsSeen =
function youtubeAccount_markAllMeNotificationsSeen(aType) {
this._logger.debug(".markAllMeNotificationsSeen('" + aType + "')");
var c_acct = this._coop.get(this.urn);
switch (aType) {
case "meMessages":
c_acct.accountMessages = 0;
break;
default:
break;
}
}
youtubeAccount.prototype.getFriendActions =
function youtubeAccount_getFriendActions(aFriendURN)
{
this._logger.info(".getFriendActions('" + aFriendURN + "')");
var actionNames = ["friendMessage",
"friendViewProfile",
"friendMediaFave",
"friendShareFlock"];
var sbs = Cc["@mozilla.org/intl/stringbundle;1"]
.getService(Ci.nsIStringBundleService);
var bundle = sbs.createBundle(YOUTUBE_STRING_BUNDLE);
var actions = [];
var c_friend = this._coop.get(aFriendURN);
if (c_friend) {
var c_acct = this._coop.get(this.urn);
for each (var i in actionNames) {
actions.push({
label: bundle.GetStringFromName("flock.youtube.actions." + i),
class: i,
spec: this.webDetective.getString("youtube", i, "")
.replace("%accountid%", c_acct.accountId)
.replace("%friendid%", c_friend.accountId)
});
}
}
return JSON.toString(actions);
}
youtubeAccount.prototype.getSharingAction =
function youtubeAccount_getSharingAction(aFriendURN, aTransferable)
{
this._logger.info(".getSharingAction('" + aFriendURN + "')");
var sharingAction = "";
var c_friend = this._coop.get(aFriendURN);
if (c_friend) {
var flavors = ["text/x-flock-media",
"text/x-moz-url",
"text/unicode",
"text/html"];
var message = Cc[FLOCK_RDDS_CONTRACTID]
.getService(Ci.flockIRichDNDService)
.getMessageFromTransferable(aTransferable,
flavors.length,
flavors);
if (!message.body) {
return sharingAction;
} else {
var videoId = this.service.getVideoIDFromUrl(message.body);
if (videoId) {
sharingAction = this.webDetective.getString("youtube",
"shareAction_sharevideo",
"");
} else {
sharingAction = this.webDetective.getString("youtube",
"shareAction_privatemessage",
"");
}
}
}
this._logger.info(sharingAction);
return sharingAction;
}
youtubeAccount.prototype.getProfileURLForFriend =
function youtubeAccount_getProfileURLForFriend(aFriendURN)
{
this._logger.info(".getProfileURLForFriend('" + aFriendURN + "')");
var url = "";
var c_friend = this._coop.get(aFriendURN);
if (c_friend) {
url = this.webDetective.getString("youtube", "friendprofile", "")
.replace("%accountid%", c_friend.accountId);
}
return url;
}
youtubeAccount.prototype.getPostLinkAction =
function youtubeAccount_getPostLinkAction(aTransferable)
{
return "";
}
// END flockISocialWebServiceAccount interface
// BEGIN flockIYoutubeAccount interface
youtubeAccount.prototype.shareFlock =
function youtubeAccount_shareFlock(aFriendURN)
{
this._logger.info(".shareFlock('" + aFriendURN + "')");
var sbs = Cc["@mozilla.org/intl/stringbundle;1"]
.getService(Ci.nsIStringBundleService);
var bundle = sbs.createBundle(YOUTUBE_STRING_BUNDLE);
var body = bundle.GetStringFromName("flock.youtube.friendShareFlock.message");
var subj = bundle.GetStringFromName("flock.youtube.friendShareFlock.subject");
this._composeMessage(aFriendURN, subj, body, false);
}
youtubeAccount.prototype.youtubePrivateMessage =
function YoutubeAccount_youtubePrivateMessage(aFriendURN, aTransferable)
{
this._logger.info(".youtubePrivateMessage('" + aFriendURN + "')");
var flavors = ["text/x-flock-media",
"text/x-moz-url",
"text/unicode",
"text/html"];
var message = Cc[FLOCK_RDDS_CONTRACTID]
.getService(Ci.flockIRichDNDService)
.getMessageFromTransferable(aTransferable,
flavors.length,
flavors);
if (message.body) {
this._composeMessage(aFriendURN, message.subject, message.body, true);
}
}
youtubeAccount.prototype.youtubeShareVideo =
function youtubeAccount_youtubeShareVideo(aFriendURN, aTransferable)
{
this._logger.info(".youtubeShareVideo('" + aFriendURN + "')");
var flavors = ["text/x-flock-media",
"text/x-moz-url",
"text/unicode",
"text/html"];
var message = Cc[FLOCK_RDDS_CONTRACTID]
.getService(Ci.flockIRichDNDService)
.getMessageFromTransferable(aTransferable,
flavors.length,
flavors);
if (message.body) {
var inst = this;
var share_url = inst.webDetective.getString("youtube",
"shareIframeURL", "");
var obs = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
var videoId = this.service.getVideoIDFromUrl(message.body);
var url = this.webDetective.getString("youtube", "youtubeShare_URL", "")
.replace("%videoid%", videoId);
var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
var win = wm.getMostRecentWindow("navigator:browser");
var dimen = inst.webDetective.getString("youtube",
"shareAction_sharevideo_features",
"");
win.open(url, "Share", dimen);
win = wm.getMostRecentWindow("navigator:browser");
flockDocumentReadyObserver = {
observe: function openShareVideo_FormFill (aSubject, aTopic, aData) {
if (aData == share_url) {
obs.removeObserver(this, "FlockDocumentReady");
var contentWindow = win.gBrowser.docShell
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
function insertContent(aDoc, aXpathquery, aAction, aMessage) {
var formItems = aDoc.evaluate(aXpathquery, aDoc, null,
Ci.nsIDOMXPathResult.ANY_TYPE, null);
if (formItems) {
var formItem = formItems.iterateNext();
if (!formItem) {
return;
}
switch (aAction) {
case "click":
formItem.click();
break;
case "username":
if (formItem.hasAttribute("value")) {
formItem.setAttribute("value", aMessage);
}
break;
case "message":
var textNode = doc.createTextNode(aMessage);
formItem.appendChild(textNode);
break;
default:
inst._logger.debug("no action associated with " + aAction);
}
}
}
var doc = contentWindow.document;
// Insert Flock bread crumb
var breadcrumb = Cc[FLOCK_RDDS_CONTRACTID]
.getService(Ci.flockIRichDNDService)
.getBreadcrumb("plain");
if (breadcrumb) {
var webDicName = "youtubeshareVideo_message";
var xpathquery = inst.webDetective.getString("youtube",
webDicName, "");
insertContent(doc, xpathquery, "message", breadcrumb);
}
// Insert friend trying to save to into iframe
webDicName = "youtubeshareVideo_IframeXPath";
xpathquery = inst.webDetective.getString("youtube",
webDicName, "");
var formItems = doc.evaluate(xpathquery, doc, null,
Ci.nsIDOMXPathResult.ANY_TYPE, null);
if (formItems) {
var iframe = formItems.iterateNext();
if (iframe) {
var c_friend = inst._coop.get(aFriendURN);
webDicName = "youtubeshareVideo_friendCheckXPath";
xpathquery = inst.webDetective.getString("youtube", webDicName, "")
.replace("%friendname%", c_friend.name);
insertContent(iframe.contentDocument, xpathquery, "click");
}
}
}
}
};
obs.addObserver(flockDocumentReadyObserver, 'FlockDocumentReady', false);
}
}
youtubeAccount.prototype._composeMessage =
function youtubeAccount__composeMessage(aFriendURN, aSubject, aBody, addBreadCrumb)
{
var body = aBody;
var subject = aSubject;
var c_friend = this._coop.get(aFriendURN);
var url = this.webDetective.getString("youtube", "youtubeMessage_URL", "")
.replace("%friendid%", c_friend.accountId);
var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
var win = wm.getMostRecentWindow("navigator:browser");
if (win) {
var browser = win.getBrowser();
var newTab = browser.loadOneTab(url, null, null, null, false, false);
var obs = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
var inst = this;
var observer = {
observe: function openSendMessageTabForFill_observer(aContent,
aTopic,
aContextUrl)
{
var contentWindow = newTab.linkedBrowser.docShell
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
function insertContent(aWebDicString, aMessage) {
var xpathquery = inst.webDetective.getString("youtube", aWebDicString, "");
var doc = contentWindow.document;
var formItems = doc.evaluate(xpathquery, doc, null,
Ci.nsIDOMXPathResult.ANY_TYPE, null);
if (formItems) {
var formItem = formItems.iterateNext();
if (formItem.hasAttribute("value")) {
formItem.setAttribute("value", aMessage);
} else {
var textNode = doc.createTextNode(aMessage);
formItem.appendChild(textNode);
inst._logger.info("aMessage " + aMessage);
}
}
}
if (contentWindow == aContent) {
obs.removeObserver(this, "EndDocumentLoad");
insertContent("youtubemessage_subjectXPath", subject);
if (addBreadCrumb) {
// Add breadcrumb to message body
var breadcrumb = Cc[FLOCK_RDDS_CONTRACTID]
.getService(Ci.flockIRichDNDService)
.getBreadcrumb("plain");
if (breadcrumb) {
body += breadcrumb;
}
}
insertContent("youtubemessage_bodyXPath", body);
}
}
};
obs.addObserver(observer, "EndDocumentLoad", false);
}
}
// END flockIYoutubeAccount interface
// ========== END youtubeAccount class ==========
// ==============================================
// ========== BEGIN XPCOM registration ==========
// ==============================================
function createModule(aParams) {
return {
registerSelf: function (aCompMgr, aFileSpec, aLocation, aType) {
aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
aCompMgr.registerFactoryLocation( aParams.CID, aParams.componentName,
aParams.contractID, aFileSpec,
aLocation, aType );
var catMgr = Cc["@mozilla.org/categorymanager;1"]
.getService(Ci.nsICategoryManager);
if (!aParams.categories) { aParams.categories = []; }
for (var i = 0; i < aParams.categories.length; i++) {
var cat = aParams.categories[i];
catMgr.addCategoryEntry( cat.category, cat.entry,
cat.value, true, true );
}
},
getClassObject: function (aCompMgr, aCID, aIID) {
if (!aCID.equals(aParams.CID)) { throw Cr.NS_ERROR_NO_INTERFACE; }
if (!aIID.equals(Ci.nsIFactory)) { throw Cr.NS_ERROR_NOT_IMPLEMENTED; }
return { // Factory
createInstance: function (aOuter, aIID) {
if (aOuter != null) { throw Cr.NS_ERROR_NO_AGGREGATION; }
var comp = new aParams.componentClass();
if (aParams.implementationFunc) { aParams.implementationFunc(comp); }
return comp.QueryInterface(aIID);
}
};
},
canUnload: function (aCompMgr) { return true; }
};
}
// NS Module entrypoint
function NSGetModule(aCompMgr, aFileSpec) {
return createModule({
componentClass: youtubeService,
CID: YOUTUBE_CID,
contractID: YOUTUBE_CONTRACTID,
componentName: CATEGORY_COMPONENT_NAME,
implementationFunc: function (aComp) { getCompTK().addAllInterfaces(aComp); },
categories: [
{ category: "wsm-startup", entry: CATEGORY_COMPONENT_NAME, value: YOUTUBE_CONTRACTID },
{ category: "flockWebService", entry: CATEGORY_ENTRY_NAME, value: YOUTUBE_CONTRACTID },
{ category: "flockMediaProvider", entry: CATEGORY_ENTRY_NAME, value: YOUTUBE_CONTRACTID },
{ category: "flockRichContentHandler", entry: CATEGORY_ENTRY_NAME, value: YOUTUBE_CONTRACTID }
]
});
}
// ========== END XPCOM registration ==========
// HELPER STUFF
function loadSubScript(spec)
{
var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);
var context = {};
loader.loadSubScript(spec, context);
return context;
}
function loadLibraryFromSpec(aSpec)
{
var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript(aSpec);
}